package com.annual.system.wechat;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import com.annual.common.config.WechatConfig;
import com.annual.common.config.WxPayConfig;
import com.annual.common.exception.ServiceException;
import com.annual.system.domain.Order;
import com.annual.system.service.IEnterpriseBusinessService;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAPublicKeyConfig;
import com.wechat.pay.java.core.exception.HttpException;
import com.wechat.pay.java.core.exception.MalformedMessageException;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.RSACombinedNotificationConfig;
import com.wechat.pay.java.core.notification.RSAPublicKeyNotificationConfig;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;


@Component
@Slf4j
public class PayUtil {
    @Autowired
    private WxPayConfig wxPayConfig;
    @Autowired
    private WechatConfig wechatConfig;
    @Autowired
    private IEnterpriseBusinessService enterpriseBusinessService;

    static Config config = null;

    public static NotificationConfig getNotificationConfig() {
        return notificationConfig;
    }

    static NotificationConfig notificationConfig = null;

    @PostConstruct
    void initConfig(){
        log.info("加载微信支付证书开始。。。。");
        log.info("微信商户号：{}",wxPayConfig.getMchId());
        log.info("微信公钥地址：{}",wxPayConfig.getPublicKeyPath());
        log.info("微信私钥地址：{}",wxPayConfig.getPrivateKeyPath());
        log.info("微信支付公钥ID：{}",wxPayConfig.getPublicKeyId());
        log.info("微信商户证书号：{}",wxPayConfig.getMerchantSerialNumber());
        log.info("微信apiV3Key：{}",wxPayConfig.getApiV3Key());
        // 使用自动更新平台证书的RSA配置
        config = new RSAPublicKeyConfig.Builder()
                .merchantId(wxPayConfig.getMchId())
                .publicKeyFromPath(wxPayConfig.getPublicKeyPath())
                .privateKeyFromPath(wxPayConfig.getPrivateKeyPath())
                .publicKeyId(wxPayConfig.getPublicKeyId()) //微信支付公钥ID
                .merchantSerialNumber(wxPayConfig.getMerchantSerialNumber())
                .apiV3Key(wxPayConfig.getApiV3Key())
                .build();


        //公钥验签
        if(wxPayConfig.getVerifyIdentity().equals("1")){
            //默认公钥id
            // 1. 如果你使用的是微信支付公私钥，则使用 RSAPublicKeyNotificationConfig
            notificationConfig = new RSAPublicKeyNotificationConfig.Builder()
                    .publicKeyFromPath(wxPayConfig.getPublicKeyPath())
                    .publicKeyId(wxPayConfig.getPublicKeyId())
                    .apiV3Key(wxPayConfig.getApiV3Key())
                    .build();
        }else {
            //证书验签
            notificationConfig = new RSACombinedNotificationConfig.Builder()
                    .merchantId(wxPayConfig.getMchId())
                    .privateKeyFromPath(wxPayConfig.getPrivateKeyPath())
                    .merchantSerialNumber(wxPayConfig.getMerchantSerialNumber())
                    .publicKeyFromPath(wxPayConfig.getPublicKeyPath())
                    .publicKeyId(wxPayConfig.getPublicKeyId())
                    .apiV3Key(wxPayConfig.getApiV3Key())
                    .build();
        }
        log.info("加载微信支付证书结束。。。。");
    }

    public Map<String,Object> jsapi(Order order, String openId){
        if(StrUtil.isBlank(openId)){
            throw new ServiceException("没有openId不能发起支付");
        }
        // 构建service
        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal((order.getFee().multiply(BigDecimal.valueOf(100))).intValue());
        request.setAmount(amount);
        Payer payer = new Payer();
        payer.setOpenid(openId);
        request.setPayer(payer);
        request.setAppid(wechatConfig.getAppId());
        request.setMchid(wxPayConfig.getMchId());
        request.setDescription(enterpriseBusinessService.getTypeName(order.getType()));
        request.setNotifyUrl(wxPayConfig.getNotifyUrl());
        request.setOutTradeNo(order.getOutTradeNo());

        // 调用下单方法，得到应答
        try {
            PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
            Map<String,Object> param = new HashMap<>();
            param.put("package", response.getPackageVal());
            param.put("nonceStr", response.getNonceStr());
            param.put("timeStamp", response.getTimeStamp());
            param.put("paySign", response.getPaySign());
            param.put("signType", response.getSignType());
            return param;
        }catch (com.wechat.pay.java.core.exception.ServiceException e){
            e.printStackTrace();
            throw new ServiceException("微信支付失败:"+e.getErrorMessage());
        }catch (Exception e){
            e.printStackTrace();
            throw new ServiceException("微信支付失败");
        }
    }


    public CreateRequest refund(Order order){
        // 初始化服务
        RefundService service = new RefundService.Builder().config(config).build();
        CreateRequest request = new CreateRequest();
        try {
            AmountReq amount = new AmountReq();
            amount.setTotal(order.getFee().multiply(BigDecimal.valueOf(100)).longValue());
            amount.setRefund(order.getFee().multiply(BigDecimal.valueOf(100)).longValue());
            amount.setCurrency("CNY");
            request.setAmount(amount);
            request.setOutTradeNo(order.getOutTradeNo());
            request.setOutRefundNo(UUID.fastUUID().toString().replaceAll("-",""));
            Refund response = service.create(request);
            log.info("退款支付返回",response.toString());
            return request;
        } catch (HttpException e) { // 发送HTTP请求失败
            e.printStackTrace();
            throw new ServiceException("退款失败");
            // 调用e.getHttpRequest()获取请求打印日志或上报监控，更多方法见HttpException定义
        } catch (ServiceException e) { // 服务返回状态小于200或大于等于300，例如500
            e.printStackTrace();
            throw new ServiceException("退款失败：返回体打印日志或上报监控");
            // 调用e.getResponseBody()获取返回体打印日志或上报监控，更多方法见ServiceException定义
        } catch (MalformedMessageException e) { // 服务返回成功，返回体类型不合法，或者解析返回体失败
            e.printStackTrace();
            throw new ServiceException("退款失败：解析返回体失败");
            // 调用e.getMessage()获取信息打印日志或上报监控，更多方法见MalformedMessageException定义
        }
    }


}
